bitkeeper revision 1.1108.35.2 (4108f181qIC17s1k7tUAzAMnlIZwBA)
authormjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Thu, 29 Jul 2004 12:45:53 +0000 (12:45 +0000)
committermjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Thu, 29 Jul 2004 12:45:53 +0000 (12:45 +0000)
Add support for getting the xend log.
Needed response headers and mime-types in the xend client code.
Add command groups in xm help.

.rootkeys
tools/python/xen/xend/XendClient.py
tools/python/xen/xend/XendDmesg.py
tools/python/xen/xend/XendLogging.py
tools/python/xen/xend/server/SrvDmesg.py
tools/python/xen/xend/server/SrvNode.py
tools/python/xen/xend/server/SrvXendLog.py [new file with mode: 0644]
tools/python/xen/xm/main.py
tools/python/xen/xm/shutdown.py

index 2324eb9159eacea20e17c6c648729adbe3697ccd..057be97bd7f3f74c24d12b461afb81b1a92da9f9 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 40c9c469TaZ83ypsrktmPSHLEZiP5w tools/python/xen/xend/server/SrvRoot.py
 40c9c469W3sgDMbBJYQdz5wbQweL0Q tools/python/xen/xend/server/SrvServer.py
 40c9c469aq7oXrE1Ngqf3_lBqL0RoQ tools/python/xen/xend/server/SrvVnetDir.py
+4108f181GtRoD1U9TBuJXMfBbGJwdQ tools/python/xen/xend/server/SrvXendLog.py
 40c9c469Y_aimoOFfUZoS-4eV8gEKg tools/python/xen/xend/server/__init__.py
 40c9c4692hckPol_EK0EGB16ZyDsyQ tools/python/xen/xend/server/blkif.py
 40c9c469N2-b3GqpLHHHPZykJPLVvA tools/python/xen/xend/server/channel.py
index 3846fbce76c12e0ceb2831eda1b0a4234d72dd3c..1bb7a094f271ddbceeb0058c3e285449e33d0472 100644 (file)
@@ -130,7 +130,6 @@ class XendRequest:
 class XendClientProtocol:
     """Abstract class for xend clients.
     """
-
     def xendRequest(self, url, method, args=None):
         """Make a request to xend.
         Implement in a subclass.
@@ -176,6 +175,9 @@ class XendClientProtocol:
         """Handle the data returned in response to the request.
         """
         if data is None: return None
+        type = self.getHeader('Content-Type')
+        if type != sxp.mime_type:
+            return data
         try:
             pin = sxp.Parser()
             pin.input(data);
@@ -194,11 +196,22 @@ class XendClientProtocol:
         """
         raise err
 
+    def getHeader(self, key):
+        """Get a header from the response.
+        Case is ignored in the key.
+
+        @param key: header key
+        @return: header
+        """
+        raise NotImplementedError()
+
 class SynchXendClientProtocol(XendClientProtocol):
     """A synchronous xend client. This will make a request, wait for
     the reply and return the result.
     """
 
+    resp = None
+
     def xendRequest(self, url, method, args=None):
         """Make a request to xend.
 
@@ -211,6 +224,7 @@ class SynchXendClientProtocol(XendClientProtocol):
         if DEBUG: conn.set_debuglevel(1)
         conn.request(method, url.fullpath(), self.request.data, self.request.headers)
         resp = conn.getresponse()
+        self.resp = resp
         val = self.handleStatus(resp.version, resp.status, resp.reason)
         if val is None:
             data = None
@@ -220,6 +234,10 @@ class SynchXendClientProtocol(XendClientProtocol):
         val = self.handleResponse(data)
         return val
 
+    def getHeader(self, key):
+        return self.resp.getheader(key)
+
+
 class AsynchXendClient(http.HTTPClient):
     """A subclass of twisted's HTTPClient to deal with a connection to xend.
     Makes the request when connected, and delegates handling responses etc.
@@ -245,6 +263,9 @@ class AsynchXendClient(http.HTTPClient):
     def handleStatus(self, version, status, message):
         return self.protocol.handleStatus(version, status, message)
 
+    def handleHeader(self, key, val):
+        return self.protocol.handleHeader(key, val)
+
     def handleResponse(self, data):
         return self.protocol.handleResponse(data)
 
@@ -257,11 +278,12 @@ class AsynchXendClientProtocol(XendClientProtocol):
     """
     def __init__(self):
         self.err = None
+        self.headers = {}
 
     def xendRequest(self, url, method, args=None):
         """Make a request to xend. The returned deferred is called when
         the result is available.
-
+        
         @param url:    xend request url
         @param method: http method: POST or GET
         @param args:   request arguments (dict)
@@ -287,46 +309,11 @@ class AsynchXendClientProtocol(XendClientProtocol):
     def handleException(self, err):
         return self.callErrback(err)
 
-    def handleResponse(self, data):
-        if self.err: return self.err
-        val = XendClientProtocol.handleResponse(self, data)
-        if isinstance(val, Exception):
-            self.callErrback(val)
-        else:
-            self.callCallback(val)
-        return val
-
-    def __init__(self):
-        self.err = None
-
-    def xendRequest(self, url, method, args=None):
-        """Make a request to xend. The returned deferred is called when
-        the result is available.
-        
-        @param url:    xend request url
-        @param method: http method: POST or GET
-        @param args:   request arguments (dict)
-        @return: deferred
-        """
-        request = XendRequest(url, method, args)
-        self.deferred = Deferred()
-        clientCreator = ClientCreator(reactor, AsynchXendClient, self, request)
-        clientCreator.connectTCP(url.host, url.port)
-        return self.deferred
-
-    def callErrback(self, err):
-        if not self.deferred.called:
-            self.err = err
-            self.deferred.errback(err)
-        return err
-
-    def callCallback(self, val):
-        if not self.deferred.called:
-            self.deferred.callback(val)
-        return val
+    def handleHeader(self, key, val):
+        self.headers[key.lower()] = val
 
-    def handleException(self, err):
-        return self.callErrback(err)
+    def getHeader(self, key):
+        return self.headers.get(key.lower())
 
     def handleResponse(self, data):
         if self.err: return self.err
@@ -397,9 +384,6 @@ class Xend:
     def eventurl(self, id=''):
         return self.url.relative('event/' + str(id))
 
-    def dmesgurl(self, id=''):
-        return self.url.relative('node/dmesg/' + str(id))
-
     def xend(self):
         return self.xendGet(self.url)
 
@@ -408,14 +392,17 @@ class Xend:
         
     def xend_node_shutdown(self):
         return self.xendPost(self.nodeurl(),
-                {'op'      : 'shutdown'})
+                             {'op'      : 'shutdown'})
                 
     def xend_node_restart(self):
         return self.xendPost(self.nodeurl(),
-                {'op'      : 'reboot'})
+                             {'op'      : 'reboot'})
 
     def xend_node_dmesg(self):
-        return self.xendGet(self.dmesgurl())
+        return self.xendGet(self.nodeurl('dmesg'))
+
+    def xend_node_log(self):
+        return self.xendGet(self.nodeurl('log'))
 
     def xend_node_cpu_rrobin_slice_set(self, slice):
         return self.xendPost(self.nodeurl(),
index b4a5ca9cad0ad6374dc3717646d4f2c0a3247454..8d070ba45a86a80e7560f472d9e0db94f5a027ea 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+ # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
 
 """Get dmesg output for this node.
 """
@@ -11,7 +11,7 @@ class XendDmesg:
         self.xc = xen.lowlevel.xc.new()
 
     def info(self):
-        return [ self.xc.readconsolering() ]
+        return self.xc.readconsolering()
         
 
 def instance():
index 106345e36a23171d991543b9bdc5515d3bf4ff79..9be84b834cce42fb023e5c71a84c4b906f58c001 100644 (file)
@@ -44,6 +44,7 @@ class XendLogging:
                                            mode='a',
                                            maxBytes=self.maxBytes,
                                            backupCount=self.backupCount)
+        self.logfilename = filename
         self.logfile.setFormatter(Formatter(self.logFileFormat, self.dateFormat))
         log = self.getLogger()
         log.addHandler(self.logfile)
@@ -51,6 +52,9 @@ class XendLogging:
     def getLogFile(self):
         return self.logfile
 
+    def getLogFilename(self):
+        return self.logfilename
+
     def initLogStderr(self):
         self.logstderr = StreamHandler()
         self.logstderr.setFormatter(Formatter(self.logStderrFormat, self.dateFormat))
index 7580ecded7c893327b2fe2837149932f6352782b..2e7b538c55319748ac329a72b10f2020e17b82e5 100644 (file)
@@ -1,10 +1,12 @@
 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
 
 import os
-from SrvDir import SrvDir
+
 from xen.xend import sxp
 from xen.xend import XendDmesg
 
+from SrvDir import SrvDir
+
 class SrvDmesg(SrvDir):
     """Xen Dmesg output.
     """
@@ -16,13 +18,13 @@ class SrvDmesg(SrvDir):
     def render_GET(self, req):
         try:
             if self.use_sxp(req):
-                req.setHeader("Content-Type", sxp.mime_type)
-                sxp.show(['dmesg'] + self.info(), out=req)
+                req.setHeader("Content-Type", "text/plain")
+                req.write(self.info())
             else:
                 req.write('<html><head></head><body>')
-                req.write('<pre>')
                 self.print_path(req)
-                req.write(self.info()[0])
+                req.write('<pre>')
+                req.write(self.info())
                 req.write('</pre></body></html>')
             return ''
         except Exception, ex:
index e99526fabf45dd3e3bf0caa05a22853c02c16ed2..b68b33ea84cbe835412a1e867df301017fa3445b 100644 (file)
@@ -1,6 +1,7 @@
 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
 
 import os
+
 from SrvDir import SrvDir
 from xen.xend import sxp
 from xen.xend import XendNode
@@ -14,6 +15,7 @@ class SrvNode(SrvDir):
         SrvDir.__init__(self)
         self.xn = XendNode.instance()
         self.add('dmesg', 'SrvDmesg')
+        self.add('log', 'SrvXendLog')
 
     def op_shutdown(self, op, req):
         val = self.xn.shutdown()
@@ -58,7 +60,8 @@ class SrvNode(SrvDir):
                 req.write('<ul>')
                 for d in self.info():
                     req.write('<li> %10s: %s' % (d[0], str(d[1])))
-                req.write('<li><a href="' + url + 'dmesg">Xen dmesg output</a>')
+                req.write('<li><a href="%sdmesg">Xen dmesg output</a>' % url)
+                req.write('<li><a href="%slog>Xend log</a>' % url)
                 req.write('</ul>')
                 req.write('</body></html>')
             return ''
diff --git a/tools/python/xen/xend/server/SrvXendLog.py b/tools/python/xen/xend/server/SrvXendLog.py
new file mode 100644 (file)
index 0000000..0edb110
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+from twisted.web import static
+
+from xen.xend import XendRoot
+
+from SrvDir import SrvDir
+
+class SrvXendLog(SrvDir):
+    """Xend log.
+    """
+
+    def __init__(self):
+        SrvDir.__init__(self)
+        logging = XendRoot.instance().get_logging()
+        self.logfile = static.File(logging.getLogFilename(), defaultType="text/plain")
+        self.logfile.type = "text/plain"
+        self.logfile.encoding = None
+
+    def render_GET(self, req):
+        try:
+            return self.logfile.render(req)
+        except Exception, ex:
+            self._perform_err(ex, req)
index 0d53836c57076a42109fad6eb9eaa6abec74eb41..d05a29d0380ef477fdc772a30f65e8ed9cceeec4 100644 (file)
@@ -13,6 +13,39 @@ from xen.xend.XendClient import XendError, server
 from xen.xend.XendClient import main as xend_client_main
 from xen.xm import create, destroy, shutdown
 
+class Group:
+
+    name = ""
+    info = ""
+    
+    def __init__(self, xm):
+        self.xm = xm
+        self.progs = {}
+
+    def addprog(self, prog):
+        self.progs[prog.name] = prog
+
+    def getprog(self, name):
+        return self.progs.get(name)
+
+    def proglist(self):
+        kl = self.progs.keys()
+        kl.sort()
+        return [ self.getprog(k) for k in kl ]
+
+    def help(self, args):
+        if self.info:
+            print 
+            print self.info
+            print
+        else:
+            print
+        
+    def shortHelp(self, args):
+        self.help(args)
+        for p in self.proglist():
+            p.shortHelp(args)
+
 class Prog:
     """Base class for sub-programs.
     """
@@ -61,6 +94,7 @@ class Xm:
         self.name = 'xm'
         self.unknown = ProgUnknown(self)
         self.progs = {}
+        self.groups = {}
 
     def err(self, msg):
         print >>sys.stderr, "Error:", msg
@@ -101,6 +135,7 @@ class Xm:
         """
         p = pklass(self)
         self.progs[p.name] = p
+        self.getgroup(p.group).addprog(p)
         return p
 
     def getprog(self, name, val=None):
@@ -123,26 +158,57 @@ class Xm:
 
         return self.progs.get(match, val)
 
-    def proglist(self):
-        """Get a list of sub-programs, ordered by group.
-        """
-        groups = {}
-        for p in self.progs.values():
-            l = groups.get(p.group, [])
-            l.append(p)
-            groups[p.group] = l
-        kl = groups.keys()
+    def group(self, klass):
+        g = klass(self)
+        self.groups[g.name] = g
+        return g
+
+    def getgroup(self, name):
+        return self.groups[name]
+
+    def grouplist(self):
+        kl = self.groups.keys()
         kl.sort()
-        pl = []
-        for k in kl:
-            l = groups[k]
-            l.sort()
-            pl += l
-        return pl
+        return [ self.getgroup(k) for k in kl ]
         
 # Create the application object, then add the sub-program classes.
 xm = Xm()
 
+class GroupAll(Group):
+
+    name = "all"
+    info = ""
+
+xm.group(GroupAll)
+
+class GroupDomain(Group):
+
+    name = "domain"
+    info = "Commands on domains:"
+    
+xm.group(GroupDomain)
+
+class GroupScheduler(Group):
+
+    name = "scheduler"
+    info = "Comands controlling scheduling:"
+
+xm.group(GroupScheduler)
+
+class GroupHost(Group):
+
+    name = "host"
+    info = "Commands related to the xen host (node):"
+
+xm.group(GroupHost)
+
+class GroupConsole(Group):
+
+    name = "console"
+    info = "Commands related to consoles:"
+
+xm.group(GroupConsole)
+
 class ProgHelp(Prog):
 
     name = "help"
@@ -157,8 +223,8 @@ class ProgHelp(Prog):
             else:
                 print '%s: Unknown command: %s' % (self.name, name)
         else:
-            for p in self.xm.proglist():
-                p.shortHelp(args)
+            for g in self.xm.grouplist():
+                g.shortHelp(args)
             print "\nTry '%s help CMD' for help on CMD" % self.xm.name
 
     main = help
@@ -220,7 +286,7 @@ xm.prog(ProgRestore)
 class ProgList(Prog):
     group = 'domain'
     name = "list"
-    info = """List info about domains."""
+    info = """List information about domains."""
 
     short_options = 'l'
     long_options = ['long']
@@ -512,7 +578,7 @@ class ProgConsole(Prog):
     info = """Open a console to a domain."""
     
     def help(self, args):
-        print "console DOM"
+        print args[0], "DOM"
         print "\nOpen a console to domain DOM."
 
     def main(self, args):
@@ -533,7 +599,7 @@ class ProgCall(Prog):
     info = "Call xend api functions."
 
     def help (self, args):
-        print "call fn argss..."
+        print args[0], "function args..."
         print """
         Call a xend HTTP API function. The leading 'xend_' on the function
 can be omitted. See xen.xend.XendClient for the API functions.
@@ -550,9 +616,19 @@ class ProgDmesg(Prog):
     info  = """Print Xen boot output."""
 
     def main(self, args):
-        print server.xend_node_dmesg()[1]
+        print server.xend_node_dmesg()
 
 xm.prog(ProgDmesg)
 
+class ProgLog(Prog):
+    group = 'host'
+    name  =  "log"
+    info  = """Print the xend log."""
+
+    def main(self, args):
+        print server.xend_node_log()
+
+xm.prog(ProgLog)
+
 def main(args):
     xm.main(args)
index a36c1a6b90de743a07e2d9e791b3d60872196a7b..73324ddd40d2f6065ea1d2cfd5ec817c0cd87003 100644 (file)
@@ -9,7 +9,8 @@ import time
 from xen.xend.XendClient import server
 from xen.xm.opts import *
 
-DOM0 = 'Domain-0'
+DOM0_NAME = 'Domain-0'
+DOM0_ID = '0'
 
 gopts = Opts(use="""[options] [DOM]
 
@@ -38,8 +39,9 @@ gopts.opt('reboot', short='R',
 
 def shutdown(opts, doms, mode, wait):
     if doms == None: doms = server.xend_domains()
-    if DOM0 in doms:
-        doms.remove(DOM0)
+    for x in [DOM0_NAME, DOM0_ID]:
+        if x in doms:
+            doms.remove(x)
     for d in doms:
         server.xend_domain_shutdown(d, mode)
     if wait: